package cn.blnp.net.flowable.boot.localize.flow.migration;

import cn.blnp.net.flowable.boot.service.TaskRecallService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.*;
import org.flowable.engine.migration.ActivityMigrationMapping;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.List;

/**
 * <h3>流程实例跨版本迁移案例</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/6/20 13:54
 */
@Slf4j
@SpringBootTest
public class FlowMigrationTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IdentityService identityService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private TaskRecallService taskRecallService;
    @Resource
    private ProcessMigrationService processMigrationService;

    /**
     * <p><b>用途:旧版迁移至新版<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 14:02 2025/6/20
     * @params [] 
     * @param  
     * @return void
    **/
    @Test
    public void testOldToNew() {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/migrateProcessInstanceOldProcess.bpmn20.xml")
                .addClasspathResource("flow/migrateProcessInstanceNewProcess.bpmn20.xml")
                .name("跨版本迁移-旧版至新版案例")
                .deploy();
        log.info("部署ID：{}", deploy.getId());
        //流程定义信息
        List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .list();
        //旧版流程定义
        ProcessDefinition oldProDef = definitionList.stream()
                .filter(info -> info.getKey().equals("migrateProcessInstanceOldProcess"))
                .findFirst()
                .orElse(null);
        ProcessDefinition newProDef = definitionList.stream()
                .filter(info -> info.getKey().equals("migrateProcessInstanceNewProcess"))
                .findFirst()
                .orElse(null);
        log.info("（旧版）流程定义ID：{}", oldProDef.getId());
        log.info("（新版）流程定义ID：{}", newProDef.getId());

        //启动旧版下的流程
        ProcessInstance procInst = runtimeService.startProcessInstanceById(oldProDef.getId());
        log.info("迁移前流程实例所在的流程定义为{}", procInst.getProcessDefinitionId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        //查询并完成第一个任务
        Task firstTask = taskQuery.singleResult();
        taskService.complete(firstTask.getId());

        //流程迁移校验
        boolean migrationValid = processMigrationService
                .createProcessInstanceMigrationBuilder()
                .migrateToProcessDefinition(newProDef.getId())
                .validateMigration(procInst.getId())
                .isMigrationValid();
        log.info("流程迁移校验结果为：{}", migrationValid);
        if (!migrationValid) {
            //校验不通过
            log.info("迁移校验不通过，无法迁移！");
            return;
        }

        //校验通过后执行流程迁移
        processMigrationService.createProcessInstanceMigrationBuilder()
                .migrateToProcessDefinition(newProDef.getId())
                .migrate(procInst.getId());
        procInst = runtimeService.createProcessInstanceQuery()
                .processInstanceId(procInst.getId()).singleResult();
        log.info("迁移后流程实例所在的流程定义为{}", procInst.getProcessDefinitionId());
        
        /**
         *  演示结果：
         *  2025-06-20 14:04:24.720  INFO 15652 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 部署ID：272501
         * 2025-06-20 14:04:24.730  INFO 15652 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : （旧版）流程定义ID：migrateProcessInstanceOldProcess:1:272507
         * 2025-06-20 14:04:24.730  INFO 15652 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : （新版）流程定义ID：migrateProcessInstanceNewProcess:1:272506
         * 2025-06-20 14:04:24.814  INFO 15652 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 迁移前流程实例所在的流程定义为migrateProcessInstanceOldProcess:1:272507
         * 2025-06-20 14:04:24.942  INFO 15652 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 流程迁移校验结果为：true
         * 2025-06-20 14:04:25.047  INFO 15652 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 迁移后流程实例所在的流程定义为migrateProcessInstanceNewProcess:1:272506
         **/
    }
    
    /**
     * <p><b>用途:新版迁移至旧版<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 14:46 2025/6/20
     * @params [] 
     * @param  
     * @return void
    **/
    @Test
    public void testNewToOld() {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/migrateProcessInstanceOldProcess.bpmn20.xml")
                .addClasspathResource("flow/migrateProcessInstanceNewProcess.bpmn20.xml")
                .name("跨版本迁移-新版至旧版案例")
                .deploy();
        log.info("部署ID：{}", deploy.getId());
        //流程定义信息
        List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .list();
        //旧版流程定义
        ProcessDefinition oldProcDef = definitionList.stream()
                .filter(info -> info.getKey().equals("migrateProcessInstanceOldProcess"))
                .findFirst()
                .orElse(null);
        ProcessDefinition newProcDef = definitionList.stream()
                .filter(info -> info.getKey().equals("migrateProcessInstanceNewProcess"))
                .findFirst()
                .orElse(null);
        log.info("（旧版）流程定义ID：{}", oldProcDef.getId());
        log.info("（新版）流程定义ID：{}", newProcDef.getId());

        //启动新版下的流程
        ProcessInstance procInst = runtimeService
                .startProcessInstanceById(newProcDef.getId());
        log.info("迁移前流程实例所在的流程定义为{}", procInst.getProcessDefinitionId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        //查询并完成第一个任务
        Task firstTask = taskQuery.singleResult();
        taskService.complete(firstTask.getId());
        //办理完成“直属上级审批”“物料管理员审批”用户任务
        List<Task> taskList = taskQuery.list();
        taskList.stream().forEach(task -> {
            log.info("办理完成任务：{}", task.getName());
            taskService.complete(task.getId());
        });
        //流程迁移校验
        boolean migrationValid = processMigrationService
                .createProcessInstanceMigrationBuilder()
                .migrateToProcessDefinition(oldProcDef.getId())
                .validateMigration(procInst.getId())
                .isMigrationValid();
        log.info("流程迁移校验结果为：{}", migrationValid);
        if (!migrationValid) {
            //校验不通过
            log.info("迁移校验不通过，无法迁移！");
            return;
        }
        //校验通过后执行流程迁移
        processMigrationService.createProcessInstanceMigrationBuilder()
                .migrateToProcessDefinition(oldProcDef.getId())
                .migrate(procInst.getId());
        procInst = runtimeService.createProcessInstanceQuery()
                .processInstanceId(procInst.getId()).singleResult();
        log.info("迁移后流程实例所在的流程定义为{}", procInst.getProcessDefinitionId());

        /**
         *  演示结果：
         *  2025-06-20 14:54:15.472  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 部署ID：275001
         * 2025-06-20 14:54:15.480  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : （旧版）流程定义ID：migrateProcessInstanceOldProcess:2:275007
         * 2025-06-20 14:54:15.480  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : （新版）流程定义ID：migrateProcessInstanceNewProcess:2:275006
         * 2025-06-20 14:54:15.559  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 迁移前流程实例所在的流程定义为migrateProcessInstanceNewProcess:2:275006
         * 2025-06-20 14:54:15.735  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 办理完成任务：直属上级审批
         * 2025-06-20 14:54:15.781  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 办理完成任务：物料管理员审批
         * 2025-06-20 14:54:15.842  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 流程迁移校验结果为：false
         * 2025-06-20 14:54:15.842  INFO 45796 --- [           main] c.b.n.f.b.l.f.m.FlowMigrationTest        : 迁移校验不通过，无法迁移！
         **/
    }
}
